package com.brid.aop.aspectj;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.brid.aop.anno.MethodParamLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

import static com.alibaba.fastjson.JSON.toJSONStringWithDateFormat;

/**
 * @Author:刘赵强
 * @Date:2020/3/4 16:33
 * @Description:AOP实现方法入参和返回值的日志打印
 **/
@Aspect
@Component
@Slf4j
public class MethodParamLogAspect {
    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String STRING_START = "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
    private static final String STRING_END = "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n";


    @Pointcut("@annotation(com.brid.aop.anno.MethodParamLog)")
    public void methodParamLogPointcut() {
    }

    @Around("methodParamLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        StringBuilder classAndMethod = new StringBuilder();
         MethodParamLog methodAnnotation = method.getAnnotation(MethodParamLog.class);
        if (methodAnnotation != null) {
            classAndMethod.append(methodAnnotation.value());
        }
        String target = targetClass.getName() + "#" + method.getName();

        Object[] args = joinPoint.getArgs();
        for (int index = 0; index < method.getParameterTypes().length; index++) {
            // 如果参数类型是请求和响应的http，则不需要拼接【这两个参数，使用JSON.toJSONString()转换会抛异常】
            if (args[index] instanceof HttpServletRequest
                    || args[index] instanceof HttpServletResponse) {
                args[index] = null;
            }
        }
        String params = toJSONStringWithDateFormat(args, DATE_FORMAT, SerializerFeature.WriteMapNullValue);
        log.info(STRING_START + "{} 开始调用--> {} 参数:{}", classAndMethod.toString(), target, params);
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long timeConsuming = System.currentTimeMillis() - start;
        log.info("\n{} 调用结束<-- {} 返回值:{} 耗时:{}ms" + STRING_END, classAndMethod.toString(), target,
                toJSONStringWithDateFormat(result, DATE_FORMAT, SerializerFeature.WriteMapNullValue), timeConsuming);
        return result;
    }
}
